package com.kuisama.oss;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.kuisama.oss.properties.AliyunOssProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 通用上传处理
 *
 * @author kuisama
 */
@Slf4j
public class AliyunOssUploadHandler {

    /**
     * listFiles 列举文件
     * 列举文件。 prefix，则列举存储空间下所有的文件。反之prefix，则列举包含指定前缀的文件。
     */
    public static List<String> listFiles(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String prefix) {
        ObjectListing objectListing = ossClient.listObjects(aliyunOssProperties.getBucketName(), prefix);
        List<OSSObjectSummary> ossObjectSummaries = objectListing.getObjectSummaries();
        List<String> keys = new ArrayList<>();
        for (OSSObjectSummary ossObjectSummary : ossObjectSummaries) {
            log.info("key name:{}", ossObjectSummary.getKey());
            keys.add(ossObjectSummary.getKey());
        }
        return keys;
    }

    /**
     * DeleteSpecifiedPrefixFile 删除指定前缀文件
     * 列举所有包含指定前缀的文件并删除
     */
    public static List<String> deleteSpecifiedPrefixFile(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String prefix) {
        String bucketName = aliyunOssProperties.getBucketName();
        String nextMarker = null;
        List<String> keys = new ArrayList<>();
        ObjectListing objectListing = null;
        do {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
                    .withPrefix(prefix)
                    .withMarker(nextMarker);
            objectListing = ossClient.listObjects(listObjectsRequest);
            if (objectListing.getObjectSummaries().size() > 0) {
                for (OSSObjectSummary ossObjectSummary : objectListing.getObjectSummaries()) {
                    log.info("key name:{}", ossObjectSummary.getKey());
                    keys.add(ossObjectSummary.getKey());
                }
                List<String> files = new ArrayList<>(keys.size());
                keys.forEach(item -> files.add(aliyunOssProperties.getHome().concat("/").concat(item)));
                DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(files);
                ossClient.deleteObjects(deleteObjectsRequest);
            }
            nextMarker = objectListing.getNextMarker();
        } while (objectListing.isTruncated());
        return keys;
    }

    /**
     * batchDeleteFile 批量删除文件
     * 删除文件。key等同于ObjectName，表示删除OSS文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
     */
    public static List<String> batchDeleteFile(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, List<String> keys) {
        List<String> files = new ArrayList<>(keys.size());
        keys.forEach(item -> files.add(aliyunOssProperties.getHome().concat("/").concat(item)));
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(aliyunOssProperties.getBucketName()).withKeys(files));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
        return deletedObjects;
    }

    /**
     * deleteFile 单个文件删除
     * 删除文件。如需删除文件夹，请将ObjectName设置为对应的文件夹名称。如果文件夹非空，则需要将文件夹下的所有object删除后才能删除该文件夹。
     */
    public static void deleteFile(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String objectName) {
        ossClient.deleteObject(aliyunOssProperties.getBucketName(), aliyunOssProperties.getHome().concat("/").concat(objectName));
    }


    /**
     * checkFileWhetherExist
     */
    public static boolean checkFileWhetherExist(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String fileName) {
        boolean whetherExist = ossClient.doesObjectExist(aliyunOssProperties.getBucketName(), aliyunOssProperties.getHome().concat("/").concat(fileName));
        return whetherExist;
    }

    /**
     * filePath上传
     */
    public static String uploadByFilePath(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String fileName, String filePath) throws Exception {
        return upload(ossClient, aliyunOssProperties, fileName, new FileInputStream(filePath));
    }

    /**
     * url上传
     */
    public static String uploadByUrl(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String fileName, String url) throws Exception {
        return upload(ossClient, aliyunOssProperties, fileName, new URL(url).openStream());
    }

    /**
     * 上传临时文件（设置过期时间不能访问，文件还是存在）
     */
    public static String upload(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String fileName, InputStream inputStream, long expireTime) throws Exception {
        String home = aliyunOssProperties.getHome();
        String cdn = aliyunOssProperties.getCdn();
        String bucketName = aliyunOssProperties.getBucketName();
        String endpoint = aliyunOssProperties.getEndpoint();
        fileName = home.concat("/").concat(fileName);
        boolean whetherIsExist = checkFileWhetherExist(ossClient, aliyunOssProperties, fileName);
        if (whetherIsExist) {
            throw new RuntimeException("the file is exist!!!");
        }
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setObjectAcl(CannedAccessControlList.PublicReadWrite);
        PutObjectRequest request = new PutObjectRequest(bucketName, fileName, inputStream, metadata);
        Date expire = new Date(System.currentTimeMillis() + expireTime * 1000);
        ossClient.putObject(request);
        inputStream.close();
        String url = ossClient.generatePresignedUrl(bucketName, fileName, expire).toString();
        log.info("url:{}", url);
        if (StringUtils.isNotBlank(cdn)) {
            return ossClient.generatePresignedUrl(bucketName, fileName, expire).toString().replaceFirst(bucketName.concat(".").concat(endpoint), aliyunOssProperties.getCdn());
        } else {
            return url;
        }
    }


    /**
     * 默认上传
     */
    public static String upload(OSSClient ossClient, AliyunOssProperties aliyunOssProperties, String fileName, InputStream inputStream) throws Exception {
        String home = aliyunOssProperties.getHome();
        String bucketName = aliyunOssProperties.getBucketName();
        boolean whetherIsExist = checkFileWhetherExist(ossClient, aliyunOssProperties, fileName);
        if (whetherIsExist) {
            throw new RuntimeException("the file is exist!!!");
        }
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setObjectAcl(CannedAccessControlList.PublicReadWrite);
        PutObjectResult putObjectResult = ossClient.putObject(bucketName, home.concat("/").concat(fileName), inputStream, metadata);
        inputStream.close();
        String url = generateUrl(aliyunOssProperties, fileName);
        log.info("url:", url);
        return url;
    }

    /**
     * 生成地址(如果cdn为空则返回oss域名)
     * oss:https://bucketNmae.oss-cn-beijing.aliyuncs.com/upload/xxx.xxx
     * cdn:https://xxx.xxx.com/upload/xxx.xxx
     */
    private static String generateUrl(AliyunOssProperties aliyunOssProperties, String fileName) {
        String cdn = aliyunOssProperties.getCdn();
        String home = aliyunOssProperties.getHome();
        if (StringUtils.isNotBlank(cdn)) {
            return String.format("https://%s/%s/%s", cdn, home, fileName);
        } else {
            return String.format("https://%s.%s/%s/%s", aliyunOssProperties.getBucketName(), aliyunOssProperties.getEndpoint(), home, fileName);
        }
    }

}
